package com.ls.fw.web.core.servlet.utils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.google.common.net.HttpHeaders;
import com.ls.fw.commons.core.utils.Encodes;

public class HttpUtils {
	public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
	private static String[] IEBrowserSignals = {"MSIE", "Trident", "Edge"};
    private	static Logger logger = LoggerFactory.getLogger(HttpUtils.class); // 判断同步或者异步发送

	// -- 常用数值定义 --//
	public static final long ONE_YEAR_SECONDS = 60 * 60 * 24 * 365;
	

	/**
	 * 设置客户端缓存过期时间 的Header.
	 */
	public static void setExpiresHeader(HttpServletResponse response, long expiresSeconds) {
		// Http 1.0 header, set a fix expires date.
		response.setDateHeader(HttpHeaders.EXPIRES, System.currentTimeMillis() + expiresSeconds * 1000);
		// Http 1.1 header, set a time after now.
		response.setHeader(HttpHeaders.CACHE_CONTROL, "private, max-age=" + expiresSeconds);
	}

	/**
	 * 设置禁止客户端缓存的Header.
	 */
	public static void setNoCacheHeader(HttpServletResponse response) {
		// Http 1.0 header
		response.setDateHeader(HttpHeaders.EXPIRES, 1L);
		response.addHeader(HttpHeaders.PRAGMA, "no-cache");
		// Http 1.1 header
		response.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0");
	}

	/**
	 * 设置LastModified Header.
	 */
	public static void setLastModifiedHeader(HttpServletResponse response, long lastModifiedDate) {
		response.setDateHeader(HttpHeaders.LAST_MODIFIED, lastModifiedDate);
	}

	/**
	 * 设置Etag Header.
	 */
	public static void setEtag(HttpServletResponse response, String etag) {
		response.setHeader(HttpHeaders.ETAG, etag);
	}

	/**
	 * 根据浏览器If-Modified-Since Header, 计算文件是否已被修改.
	 * 
	 * 如果无修改, checkIfModify返回false ,设置304 not modify status.
	 * 
	 * @param lastModified 内容的最后修改时间.
	 */
	public static boolean checkIfModifiedSince(HttpServletRequest request, HttpServletResponse response,
			long lastModified) {
		long ifModifiedSince = request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
		if ((ifModifiedSince != -1) && (lastModified < ifModifiedSince + 1000)) {
			response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			return false;
		}
		return true;
	}

	/**
	 * 根据浏览器 If-None-Match Header, 计算Etag是否已无效.
	 * 
	 * 如果Etag有效, checkIfNoneMatch返回false, 设置304 not modify status.
	 * 
	 * @param etag 内容的ETag.
	 */
	public static boolean checkIfNoneMatchEtag(HttpServletRequest request, HttpServletResponse response, String etag) {
		String headerValue = request.getHeader(HttpHeaders.IF_NONE_MATCH);
		if (headerValue != null) {
			boolean conditionSatisfied = false;
			if (!"*".equals(headerValue)) {
				StringTokenizer commaTokenizer = new StringTokenizer(headerValue, ",");

				while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
					String currentToken = commaTokenizer.nextToken();
					if (currentToken.trim().equals(etag)) {
						conditionSatisfied = true;
					}
				}
			} else {
				conditionSatisfied = true;
			}

			if (conditionSatisfied) {
				response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
				response.setHeader(HttpHeaders.ETAG, etag);
				return false;
			}
		}
		return true;
	}

	/**
	 * 设置让浏览器弹出下载对话框的Header.
	 * 
	 * @param name 下载后的文件名.
	 */
	public static void setFileDownloadHeader(HttpServletResponse response, String name) {
		try {
			// 中文文件名支持
			String encodedname = new String(name.getBytes(), "ISO8859-1");
			response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedname + "\"");
		} catch (UnsupportedEncodingException e) {
			e.getMessage();
		}
	}

	/**
	 * 取得带相同前缀的Request Parameters, copy from spring WebUtils.
	 * 
	 * 返回的结果的Parameter名已去除前缀.
	 */
	@SuppressWarnings("rawtypes")
	public static Map<String, Object> getParametersStartingWith(ServletRequest request, String prefix) {
		Validate.notNull(request, "Request must not be null");
		Enumeration paramNames = request.getParameterNames();
		Map<String, Object> params = new TreeMap<String, Object>();
		String pre = prefix;
		if (pre == null) {
			pre = "";
		}
		while (paramNames != null && paramNames.hasMoreElements()) {
			String paramName = (String) paramNames.nextElement();
			if ("".equals(pre) || paramName.startsWith(pre)) {
				String unprefixed = paramName.substring(pre.length());
				String[] values = request.getParameterValues(paramName);
				if (values == null || values.length == 0) {
					values = new String[]{};
					// Do nothing, no values found at all.
				} else if (values.length > 1) {
					params.put(unprefixed, values);
				} else {
					params.put(unprefixed, values[0]);
				}
			}
		}
		return params;
	}

	/**
	 * 组合Parameters生成Query String的Parameter部分,并在paramter name上加上prefix.
	 * 
	 */
	public static String encodeParameterStringWithPrefix(Map<String, Object> params, String prefix) {
		StringBuilder queryStringBuilder = new StringBuilder();

		String pre = prefix;
		if (pre == null) {
			pre = "";
		}
		Iterator<Entry<String, Object>> it = params.entrySet().iterator();
		while (it.hasNext()) {
			Entry<String, Object> entry = it.next();
			queryStringBuilder.append(pre).append(entry.getKey()).append("=").append(entry.getValue());
			if (it.hasNext()) {
				queryStringBuilder.append("&");
			}
		}
		return queryStringBuilder.toString();
	}

	/**
	 * 客户端对Http Basic验证的 Header进行编码.
	 */
	public static String encodeHttpBasic(String userName, String password) {
		String encode = userName + ":" + password;
		return "Basic " + Encodes.encodeBase64(encode.getBytes());
	}
	 
	/**
	 * 获取当前请求对象
	 * @return
	 */
	public static HttpServletRequest getRequest(){
		try{
			return ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
		}catch(Exception e){
			return null;
		}
	}

	public static boolean isMSBrowser(HttpServletRequest request) {
        String userAgent = request.getHeader("User-Agent");
        for (String signal : IEBrowserSignals) {
            if (userAgent.contains(signal))
                return true;
        }
        return false;
    }

    public static String decode(String name){
    	  String n = name;
         try {
    	   n = URLDecoder.decode(name, "UTF-8");
		} catch (UnsupportedEncodingException e) {
		}
        return n;
    }

    public static String decode(HttpServletRequest request,String name){
        boolean isMSIE = HttpUtils.isMSBrowser(request);
        String n = name;
        if (isMSIE) {
           try {
        	   n = URLDecoder.decode(name, "UTF-8");
			} catch (UnsupportedEncodingException e) {
			}
        } else {
           try {
				n = new String(name.getBytes("ISO-8859-1"), "UTF-8");
			} catch (UnsupportedEncodingException e) {
			}
        }
        return n;
    }
    public static String encode(String name){
        String n = name;
       try {
    	   n = URLEncoder.encode(name, "UTF-8");
		} catch (UnsupportedEncodingException e) {
		}
        return n;
    }
    public static String encode(HttpServletRequest request,String name){
        boolean isMSIE = HttpUtils.isMSBrowser(request);
        String n = name;
        if (isMSIE) {
           try {
        	   n = URLEncoder.encode(name, "UTF-8");
			} catch (UnsupportedEncodingException e) {
			}
        } else {
           try {
				n = new String(name.getBytes("UTF-8"), "ISO-8859-1");
			} catch (UnsupportedEncodingException e) {
			}
        }
        return n;
    }
    public static void encode(HttpServletRequest request,HttpServletResponse response,String name) {
        response.setContentType("application/octet-stream");
        String n = encode(request, name);
        response.setHeader("Content-disposition", "attachment;filename=\"" + n + "\"");
    }
    
    /**
	 * 得到请求的IP地址
	 * 
	 * @param request
	 * @return
	 */
	public static String getIp(HttpServletRequest request) {
		String ip = request.getHeader("X-Real-IP");
		if (StringUtils.isBlank(ip)){
			ip = request.getHeader("X-Forwarded-For");
		}
		if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	/**
	 * 得到请求的根目录
	 * 例：<code>http://localhost:8080/news/main/list.jsp</code>
	 * 返回http://localhost:8080/news
	 * @param request
	 * @return
	 */
	public static String getBasePath(HttpServletRequest request) {
		String path = request.getContextPath();
		int port = request.getServerPort();
		String portString = "";
		if(port != 80){
			portString = ":" + port;
		}
		String basePath = request.getScheme() + "://" + request.getServerName()
				+ portString + path;
		return basePath;
	}

	/**
	 * 得到结构目录。
	 * 例：<code>http://localhost:8080/news/main/list.jsp</code>
	 * 返回/news
	 * @param request
	 * @return
	 */
	public static String getContextPath(HttpServletRequest request) {
		String path = request.getContextPath();
		return path;
	}

	
	/**
	 * 生成绝对路径
	 * @author lisheng
	 * @date 2016年7月18日 下午8:27:02
	 * @version V1.0
	 * @param req
	 * @return
	 */
	public static  String genAbsolutePath(HttpServletRequest req){
    	return genAbsolutePath(req, null);
    }
    	
	
	/**
	 * 生成绝对路径
	 * 
	 * @author lisheng
	 * @date 2016年7月18日 下午8:27:21
	 * @version V1.0
	 * @param req
	 * @param url
	 * @return
	 */
    public static  String genAbsolutePath(HttpServletRequest req, String url){
    	if(StringUtils.isBlank(url)){
			return req.getContextPath();
    	}else{
    		if(url.startsWith("/")){
    			return req.getContextPath()+ url;
    		}else{
    			return req.getContextPath()+"/"+ url;
    		}
    	}
    }
	/**
	 * 
	 * 例：<code>http://localhost:8080/news/main/list.jsp</code>
	 * 返回/main/list.jsp
	 * @author lisheng
	 * @date 2016年4月26日 下午10:49:08
	 * @version V1.0
	 * @param request
	 * @return
	 */
	public static String getServletPath(HttpServletRequest request) {
		String path = request.getServletPath();
		return path;
	}
	
	/**
	 * 请求的url
	 * 例：<code>http://localhost:8080/news/main/list.jsp</code>
	 * 返回/news/main/list.jsp
	 * @author lisheng
	 * @date 2016年4月26日 下午10:45:45
	 * @version V1.0
	 * @param request
	 * @return
	 */
	public static String getRequestURL(HttpServletRequest request) {
		StringBuffer url = request.getRequestURL();
		return url.toString();
	}
	/**
	 * 根据传入的uri和参数map拼接成实际uri
	 * 
	 * @param uri
	 * @param paraMap
	 * @return
	 */
	public static String buildUri(String uri, Map<String, String> paraMap) {
		StringBuilder sb = new StringBuilder();
		uri = StringUtils.trim(uri);
		uri = StringUtils.removeEnd(uri, "/");
		uri = StringUtils.removeEnd(uri, "?");
		sb.append(uri);
		if (paraMap != null && !paraMap.isEmpty()) {
			sb.append("?");
			Iterator<Entry<String, String>> iterator = paraMap.entrySet()
					.iterator();
			while (iterator.hasNext()) {
				Map.Entry<String, String> pair = iterator.next();
				try {
					String keyString = pair.getKey();
					String valueString = pair.getValue();
					sb.append(keyString);
					sb.append("=");
					sb.append(valueString);
					sb.append("&");
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
			}
		}
		return StringUtils.removeEnd(sb.toString(), "&");
	}

	public static Map<String,Object> getAllPara(HttpServletRequest request){
		return getAllPara(request, true);
	}
	
	public static Map<String,Object> getAllPara(HttpServletRequest request, boolean copyInputStreamToString){
		Enumeration<?> pNames =  request.getParameterNames();
		Map<String, Object> params = new HashMap<String, Object>();
		while (pNames.hasMoreElements()) {
			String pName = (String) pNames.nextElement();
			Object pValue = request.getParameter(pName);
			params.put(pName, decode(pValue+""));
		}
		Map<String, String[]> paramMap = request.getParameterMap();
		Set<String> keySet = paramMap.keySet();
		for (Object objName : keySet) {
			String paramName = objName.toString();
			String[] values = (String[]) paramMap.get(objName);
			if (values != null && values.length == 1) { // 单值,多值不考虑
				params.put(paramName, decode(values[0]));
			}else if(values != null && values.length > 1){
				params.put(paramName, Arrays.toString(values));
			}else{
				params.put(paramName, null);
			}
		}
		
		String urlString  = request.getQueryString();
		if(com.ls.fw.commons.core.utils.string.StringUtils.isNotBlank(urlString)){
			String[] strs = urlString.split("&");
			for (String string : strs) {
				String[] paraStrings = string.split("=");
				String name = paraStrings[0];
				if(com.ls.fw.commons.core.utils.string.StringUtils.isNotBlank(name)){
					Object dObject = null;
					if(paraStrings.length>1){
						dObject = paraStrings[1];
					}
					if(dObject != null){
						params.put(name, decode(dObject+""));
					}else{
						params.put(name, null);
					}
				}
			}
		}
		try {
			if(copyInputStreamToString && "post".equalsIgnoreCase(request.getMethod())){
				String jsonString = StreamUtils.copyToString(request.getInputStream(), DEFAULT_CHARSET);
				if(StringUtils.isNotBlank(jsonString)){
					Map map = JSON.parseObject(jsonString,Map.class);
					if(map!=null){
						params.putAll(map);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return params;
	}
 

	public static Map<String,String> getAllParaStr(HttpServletRequest request){
		return getAllParaStr(request, true);
	}
	
	
	public static Map<String,String> getAllParaStr(HttpServletRequest request, boolean copyInputStreamToString){
		Enumeration<?> pNames =  request.getParameterNames();
		Map<String, String> params = new HashMap<String, String>();
		while (pNames.hasMoreElements()) {
			String pName = (String) pNames.nextElement();
			String pValue = request.getParameter(pName);
			params.put(pName, decode(pValue+""));
		}
		Map<String, String[]> paramMap = request.getParameterMap();
		Set<String> keySet = paramMap.keySet();
		for (Object objName : keySet) {
			String paramName = objName.toString();
			String[] values = (String[]) paramMap.get(objName);
			if (values != null && values.length == 1) { // 单值,多值不考虑
				params.put(paramName, decode(values[0]));
			}else if(values != null && values.length > 1){
				params.put(paramName, Arrays.toString(values));
			}else{
				params.put(paramName, null);
			}
		}
		
		String urlString  = request.getQueryString();
		if(com.ls.fw.commons.core.utils.string.StringUtils.isNotBlank(urlString)){
			String[] strs = urlString.split("&");
			for (String string : strs) {
				String[] paraStrings = string.split("=");
				String name = paraStrings[0];
				if(com.ls.fw.commons.core.utils.string.StringUtils.isNotBlank(name)){
					String dObject = null;
					if(paraStrings.length>1){
						dObject = paraStrings[1];
					}
					if(StringUtils.isNotBlank(dObject)){
						params.put(name, decode(dObject));
					}
				}
			}
		}
		try {
			if(copyInputStreamToString && "post".equalsIgnoreCase(request.getMethod())){
				String jsonString = StreamUtils.copyToString(request.getInputStream(), DEFAULT_CHARSET);
				if(StringUtils.isNotBlank(jsonString)){
					Map map = JSON.parseObject(jsonString,Map.class);
					if(map!=null){
						params.putAll(map);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return params;
	}
    public static void main(String[] args) throws MalformedURLException
    {
        String url = "http://127.0.0.1:8080/store/auth/login.htm?a=1;JSESSIONID=49792d7c-78bf-4bfc-9af5-5a9feed8fe1f";
        URL u = new URL(url);
        System.out.println(u);
        
    }
}